#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
from os.path import expanduser
import sys,os
import time
import errno
# import subprocess
import threading
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.topo import Topo
from mininet.node import OVSSwitch, Controller, RemoteController
from mininet.log import setLogLevel, info, debug
from socket import error as socket_error

class SwitchAgent:
    def __init__(self):
        self.managerIP = sys.argv[1]
        self.managerPort = int(sys.argv[2])
        self.interlayerPort = int(sys.argv[3])
        if sys.argv[4] == "1.3":
            self.openFlowVersion = "OpenFlow13"
            print "use OpenFlow 1.3"
        else:
            self.openFlowVersion = "OpenFlow10"
            print "use OpenFlow 1.0"
        self.server_address = (self.managerIP, int(self.managerPort))
        self.net = Mininet(topo=None, controller=None, build=False)
        # Create a TCP/IP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.running = True


    def connectServer(self):

        while self.running:
            try:
                # Connect the socket to the port where the server is listening
                if not self.server_address:
                    self.server_address = ('10.0.3.1', 3366)

                print('[connectServer] Connecting to %s port %s' % self.server_address)
                self.sock.connect(self.server_address)

                # Send AppAgent Message
                self.sock.send('SwitchAgent\n')
                print("[SwitchAgent] Handshaking with AgentManager...")

                # Receive OK Message
                msg = self.sock.recv(1024)
                print("[SwitchAgent] Received from AgentManager: " + msg)

                # Loop for communications with Agent Manager
                while self.running:
                    msg = self.sock.recv(1024)
                    self.dispose(msg)
            except socket_error as serr:
                if serr.errno == errno.ECONNREFUSED:
                    print("[SwitchAgent] Agent Manager is not listening")
            except:
                e = sys.exc_info()[0]
                print("[SwitchAgent] error: " + str(e))
            finally:
                time.sleep(5)

    def dispose(self, msg):
        # Receive Code
        print("SwitchAgent: " + msg)
        if "run mininet" in msg.lower():
            t = threading.Thread(target=self.runMininet, name='runMininet')
            t.start()
            print("===============================run mininet===========================")

        elif "stop mininet" in msg.lower():
            self.net.stop()
            os.system("sudo mn -c")
            print("===============================stop mininet===========================")

        elif "echo" in msg.lower():
            self.sock.send('echo\n')

        elif "stop agent" in msg.lower():
            self.running = False

        else:
            print("[SwitchAgent] Don't know how to process " + msg)


    def runMininet(self):
        self.net = Mininet(topo=None, controller=None, build=False)

        # Add switch
        s0 = self.net.addSwitch('s0', dpid='00:00:00:00:00:01', protocols=self.openFlowVersion)

        # Add hosts
        h1 = self.net.addHost('h1', ip='10.0.0.1', mac='00:00:00:00:00:11')
        h2 = self.net.addHost('h2', ip='10.0.0.2', mac='00:00:00:00:00:22')

        # Add links
        self.net.addLink(s0, h1)
        self.net.addLink(s0, h2)
        # connect a controller

        self.net.addController('controller', controller=RemoteController, ip=self.managerIP, port=self.interlayerPort)

        # net.build()
        self.net.start()

        # Add hardware interface to switch1

        # connect a controller
        # os.system("sudo ovs-vsctl set-controller s0 tcp:"+sys.argv[1]+":"+sys.argv[2])
        # h1.cmd("java -jar $HOME/sdnst-agent-host-1.0-SNAPSHOT.jar " + self.managerIP + " " + self.managerPort)
        # CLI(net)
        # net.pingAll()
        # net.stop()


if __name__ == "__main__":
     setLogLevel('debug')
     if len(sys.argv) != 5:
         print ("Usage: sudo python topo-setup.py <AM_IP> <AM_PORT> <Interlayer_Port> <OF_VER>")
         sys.exit(0)
     agent = SwitchAgent()
     agent.connectServer()